package org.tuio4j.profile.cursor2d;

import java.util.HashSet;
import java.util.Hashtable;

import org.tuio4j.TUIOProfileListener;
import org.tuio4j.TuioEvent;
import org.tuio4j.TuioProfile;
import org.tuio4j.message.TuioMessage;

/**
 * See license.txt for license information.
 * @author Uwe Laufs
 * @version 1.0
 */
public class Profile2DCursor extends TuioProfile {
	private final String profileAdress = "/tuio/2Dcur";
	private final Hashtable<Integer, TuioMessage> sessionIdToPreviousMessage = new Hashtable<Integer, TuioMessage>();
	public Profile2DCursor() {

	}
	@Override
	public String[] getProfileAddress() {
		return new String[]{profileAdress};
	}
	@Override
	public void consumeMessage(TuioMessage m) {
//		System.out.println("CONSUME " + m.getMessageAdress() + " " + m.getMessageArguments()[0]);
		String type = (String)m.getMessageArguments()[0];
		
		if(type.equals(MESSAGETYPE_ALIVE)){
			// CLEAN UP / FINISH SESSIONS
			HashSet<Integer> aliveFromMsg = new HashSet<Integer>();
			for (int i = 1; i < m.getMessageArguments().length; i++) {
				Integer currentAliveFromMessage = (Integer)m.getMessageArguments()[i];
				aliveFromMsg.add(currentAliveFromMessage);
			}
			Integer[] rememberedAlive = this.getAliveSessionIds();
			
			//// DEBUG CODE
			String rememberedAliveString = "rememberedAlive:";
			String tuioAliveString = "tuioAlive:";
			for (int i = 0; i < rememberedAlive.length; i++) {
				rememberedAliveString += rememberedAlive[i] + ",";
			}
			for (int i = 1; i < m.getMessageArguments().length; i++) {
				tuioAliveString += m.getMessageArguments()[i] + ",";
			}
			tuioAliveString += "m.getMessageArguments() (" + m.getMessageArguments().length + " args)";
			
//			System.out.println(rememberedAliveString);
//			System.out.println(tuioAliveString);
			////
			
			for (int i = 0; i < rememberedAlive.length; i++) {
				if(aliveFromMsg.contains(rememberedAlive[i])){
					// in both lists, everything's fine
				}else{
					this.removeAliveSessionId(rememberedAlive[i]);
//					System.out.println();
//					System.out.println("REMOVE SID:" + rememberedAlive[i].intValue());
					Tuio2DCursorEvent tuioEvent = createEndedEvent(rememberedAlive[i].intValue());
					fireTuioEvent(tuioEvent);
				}
			}
		}else if(type.equals(MESSAGETYPE_SET)){
			int sessionId = ((Integer)m.getMessageArguments()[1]).intValue();
			if(isAliveSessionId(sessionId)){
				// update or ignore if not in alive list
				Tuio2DCursorEvent tuioEvent = createUpdatedEvent(m);
				fireTuioEvent(tuioEvent);
			}else{
				// new sessionId detected
				this.addAliveSessionId(sessionId);
				Tuio2DCursorEvent tuioEvent = createDetectedEvent(m);
				fireTuioEvent(tuioEvent);
			}
		}else if(type.equals(MESSAGETYPE_FSEQ)){
			// ignore
		}else if(type.equals(MESSAGETYPE_SOURCE)){
			// ignore
		}
	}
	private Tuio2DCursorEvent createDetectedEvent(TuioMessage m){
			Tuio2DCursorEvent tuioEvent = new Tuio2DCursorEvent(TuioEvent.SESSION_DETECTED,
			((Integer)m.getMessageArguments()[1]).intValue(),
	        ((Float)m.getMessageArguments()[2]).floatValue(),
			((Float)m.getMessageArguments()[3]).floatValue(),
			((Float)m.getMessageArguments()[4]).floatValue(),
			((Float)m.getMessageArguments()[5]).floatValue(),
			((Float)m.getMessageArguments()[6]).floatValue()
		);
		// remember previous tuio message (required later)
		this.sessionIdToPreviousMessage.put(((Integer)m.getMessageArguments()[1]).intValue(), m);
		return tuioEvent;
	}
	private Tuio2DCursorEvent createUpdatedEvent(TuioMessage m){
		Tuio2DCursorEvent tuioEvent = new Tuio2DCursorEvent(
			TuioEvent.SESSION_UPDATED,
			((Integer)m.getMessageArguments()[1]).intValue(),
	        ((Float)m.getMessageArguments()[2]).floatValue(),
			((Float)m.getMessageArguments()[3]).floatValue(),
			((Float)m.getMessageArguments()[4]).floatValue(),
			((Float)m.getMessageArguments()[5]).floatValue(),
			((Float)m.getMessageArguments()[6]).floatValue()
		);
		// remember previous tuio message (required later)
		this.sessionIdToPreviousMessage.put(((Integer)m.getMessageArguments()[1]).intValue(), m);
		return tuioEvent;
	}
	private Tuio2DCursorEvent createEndedEvent(int sessionId){
		TuioMessage previousMessage = sessionIdToPreviousMessage.get(sessionId);
		float x = ((Float)previousMessage.getMessageArguments()[2]).floatValue();
		float y = ((Float)previousMessage.getMessageArguments()[3]).floatValue();
		
		// create an ended-event based on previous event (e.g. contain markerId and rotation)
		Tuio2DCursorEvent tuioEvent = new Tuio2DCursorEvent(
			TuioEvent.SESSION_ENDED,
			sessionId,
	        x,
	        y,
	        0f,
	        0f,
	        0f
		);
//		System.out.println(tuioEvent);
		// remove previous message
		this.sessionIdToPreviousMessage.remove(sessionId);
		return tuioEvent;
	}
	private void fireTuioEvent(TuioEvent event){
//		System.out.println("FIRE TUIO EVENT");
		TUIOProfileListener[] listeners = this.getListeners();
		for (int i = 0; i < listeners.length; i++) {
			listeners[i].eventProducedByProfile(this, event);
		}
	}
	
}
